 package org.springframework.remoting.server;
 
 import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.remoting.interceptor.RemoteInterceptor;
import org.springframework.remoting.rmi.RmiServiceExporter;
import org.springframework.remoting.server.util.AopTargetUtils;
import org.springframework.remoting.service.annotation.RemoteService;
import org.springframework.remoting.support.RemoteExporter;
 
 public class HttpInvokerExporterBeanFactoryPostProcessor implements BeanFactoryPostProcessor
 {
   protected static final Logger logger = LoggerFactory.getLogger(HttpInvokerExporterBeanFactoryPostProcessor.class);
   
   public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
     postProcessBeanFactory(beanFactory, beanFactory.getBeanDefinitionNames());
     ConfigurableListableBeanFactory parent = (ConfigurableListableBeanFactory)beanFactory.getParentBeanFactory();
     postProcessBeanFactory(beanFactory, parent.getBeanDefinitionNames());
   }
   
   private void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory, String[] beanDefinitionNames) {
     for (String beanName : beanDefinitionNames) {
       Object bean = beanFactory.getBean(beanName);
       Class<?> serviceInterface = findServiceInterface(bean);
       if (serviceInterface != null) {
         RemoteExporter remoteExporter = createRemoteExporter(serviceInterface, bean);
         beanFactory.registerSingleton("/" + serviceInterface.getName(), remoteExporter);
         logger.info("RemoteExporter class = {},url = /{}", remoteExporter, serviceInterface.getName());
       }
     }
   }
   
   private Class<?> findServiceInterface(Object proxy) {
     Object target = null;
     try {
       target = AopTargetUtils.getTarget(proxy);
     } catch (Exception e) {
       logger.error(e.getMessage(), e);
       target = proxy;
     }
     Class<?> serviceInterface = null;
     if (AnnotationUtils.isAnnotationDeclaredLocally(org.springframework.stereotype.Service.class, target.getClass())) {
       for (Class<?> interfaceClass : target.getClass().getInterfaces()) {
         if (AnnotationUtils.isAnnotationDeclaredLocally(RemoteService.class, interfaceClass)) {
           serviceInterface = interfaceClass;
           break;
         }
       }
     }
     return serviceInterface;
   }
   
   private RemoteExporter createRemoteExporter(Class<?> serviceInterface, Object service) {
     RemoteExporter remoteExporter = null;
     RemoteService remoteService = (RemoteService)AnnotationUtils.findAnnotation(service.getClass(), RemoteService.class);
     try {
       remoteExporter = (RemoteExporter)remoteService.serviceType().getServiceExporter().newInstance();
       remoteExporter.setService(service);
       remoteExporter.setServiceInterface(serviceInterface);
       remoteExporter.setInterceptors(new Object[]{ new RemoteInterceptor()});
       if ((remoteExporter instanceof RmiServiceExporter)) {
         ((RmiServiceExporter)remoteExporter).setServiceName(serviceInterface.getName());
         ((RmiServiceExporter)remoteExporter).setRegistryPort(remoteService.registryPort());
       }
       if ((remoteExporter instanceof InitializingBean)) {
         ((InitializingBean)remoteExporter).afterPropertiesSet();
       }
     } catch (Exception e) {
       logger.error(e.getMessage(), e);
     }
     return remoteExporter;
   }
 }